package com.example.demo;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.*;
import java.util.concurrent.TimeUnit;

@SpringBootApplication
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Fork(value = 2, jvmArgs = {"-Xms4G", "-Xmx4G"})
public class ListApplication {

    public static final Integer[] numbers = new Integer[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    public static final List<Integer> aryList = new ArrayList(Arrays.asList(numbers));
    public static final List<Integer> lnkList = new LinkedList(Arrays.asList(numbers));

    public static final Random randomIndex = new Random();

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(ListApplication.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }

    @Benchmark
    public void test01_ArrayListWriteBySequential() {
        final List<Integer> aryList = new ArrayList();
        for (int index = 0; index < numbers.length; index++) {
            aryList.add(numbers[index]);
        }
    }

    @Benchmark
    public void test02_LinkedListWriteBySequential() {
        final List<Integer> lnkList = new LinkedList();
        for (int index = 0; index < numbers.length; index++) {
            lnkList.add(numbers[index]);
        }
    }

    @Benchmark
    public void test03_ArrayListReadByStreamMap() {
        aryList.stream().map(n -> n);
    }

    @Benchmark
    public void test04_LinkedListReadByStreamMap() {
        lnkList.stream().map(n -> n);
    }

    @Benchmark
    public void test05_ArrayListReadByIteration() {
        for (Integer num : aryList) {
            num += 0;
        }
    }

    @Benchmark
    public void test06_LinkedListReadByIteration() {
        for (Integer num : lnkList) {
            num += 0;
        }
    }

    @Benchmark
    public void test07_ArrayListReadByRandomIndex() {
        aryList.get(randomIndex.nextInt(numbers.length - 1));
    }

    @Benchmark
    public void test08_LinkedListReadByRandomIndex() {
        lnkList.get(randomIndex.nextInt(numbers.length - 1));
    }

    @Benchmark
    public void test09_ArrayListWriteByRandomIndex() {
        aryList.add(randomIndex.nextInt(numbers.length - 1), 0);
    }

    @Benchmark
    public void test10_LinkedListWriteByRandomIndex() {
        lnkList.add(randomIndex.nextInt(numbers.length - 1), 0);
    }
}
